/*
 * Copyright (c) 2020-2099 the original author or authors. All rights reserve.
 */
package org.tianyun.cloud.config.console;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.core.env.Environment;
import org.springframework.util.CollectionUtils;
import org.tianyun.cloud.config.console.client.response.ComponentResponse;
import org.tianyun.cloud.config.console.client.response.ConfigRequest;
import org.tianyun.cloud.config.console.client.response.NamespaceResponse;
import org.tianyun.cloud.config.console.property.Component;
import org.tianyun.cloud.config.console.property.Route;
import org.tianyun.cloud.context.AppContext;

import java.net.InetAddress;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.stream.Collectors;

/**
 * 控制台管理器
 *
 * @author ebert_chan
 */
public final class ConsoleManager {

    private static final Logger log = LoggerFactory.getLogger(ConsoleManager.class);

    private static final Map<String, Component> componentCache = new HashMap<>();

    private static final Map<String, Properties> propertiesCache = new HashMap<>();

    public static void registerComponent(Component component) {
        synchronized (componentCache) {
            componentCache.put(component.getName(), component);
        }
    }

    public static boolean containsComponent(String name) {
        return componentCache.containsKey(name);
    }

    public static Component getComponent(String name) {
        return componentCache.get(name);
    }

    public static Map<String, Component> getAllComponents() {
        return componentCache;
    }

    public static void setProperties(String name, Properties properties) {
        synchronized (propertiesCache) {
            propertiesCache.put(name, properties);
        }
    }

    public static void removeProperties(String name) {
        synchronized (propertiesCache) {
            propertiesCache.remove(name);
        }
    }

    public static Map<String, Properties> getAllProperties() {
        return propertiesCache;
    }

    public static List<Route> routes() {
        return componentCache.values().stream()
                .map(component -> Route.prefix(component.getNamespace(), component.getName(), component.getConfigurationPrefix()))
                .collect(Collectors.toList());
    }

    public static ConfigRequest buildConfig() {
        ApplicationContext applicationContext = AppContext.getApplicationContext();
        if (applicationContext == null) {
            return null;
        }

        Environment environment = applicationContext.getEnvironment();
        String application = environment.getProperty("spring.application.name");
        String port = environment.getProperty("server.port");
        String contextPath = environment.getProperty("server.servlet.context-path");

        Map<String, Component> components = ConsoleManager.getAllComponents();
        Map<String, Properties> properties = ConsoleManager.getAllProperties();
        if (CollectionUtils.isEmpty(components)) {
            return null;
        }
        String hostAddress;
        try {
            InetAddress localHost = InetAddress.getLocalHost();
            hostAddress = localHost.getHostAddress();
        } catch (Exception e) {
            log.error("get local host address error", e);
            return null;
        }


        Map<String, NamespaceResponse> namespaces = new HashMap<>();
        for (Map.Entry<String, Component> entry : components.entrySet()) {
            Component component = entry.getValue();

            NamespaceResponse namespaceResponse = namespaces.get(component.getNamespace());
            if (namespaceResponse == null) {
                namespaceResponse = new NamespaceResponse();
                namespaceResponse.setNamespace(component.getNamespace());
                namespaceResponse.setComponents(new ArrayList<>());
                namespaces.put(component.getNamespace(), namespaceResponse);
            }

            ComponentResponse componentResponse = new ComponentResponse();
            componentResponse.setName(component.getName());
            Properties prop = properties.get(component.getName());
            if (prop != null) {
                componentResponse.setProperties(prop.entrySet().stream()
                        .map(e -> e.getKey() + "=" + (e.getValue() != null ? e.getValue().toString() : "")).collect(Collectors.joining("\r\n")));
            }

            namespaceResponse.getComponents().add(componentResponse);
        }

        ConfigRequest configRequest = new ConfigRequest();
        configRequest.setApplication(application);
        configRequest.setTimestamp(System.currentTimeMillis());
        configRequest.setNamespaces(namespaces.values().stream().collect(Collectors.toList()));
        configRequest.setIp(hostAddress);
        configRequest.setPort(port);
        configRequest.setContextPath(contextPath);

        return configRequest;
    }

}
